#pragma once
#include "OpenGL.hpp"
#include <string>
#include <sstream>
#include "SDL.h"
#include "General Structures.hpp" 


using namespace std;

static GameRectangle ScaledRect(GameRectangle rectangle, double ratio)
{
	GameRectangle ScaledRect; 
	
	double xOffset = (rectangle.width*(ratio-1)) / -2.0;
	double yOffset = (rectangle.height*(ratio-1))/ -2.0;
	
	double NewX = rectangle.x + xOffset;
	double NewX2 = rectangle.x2 - xOffset;

	double NewY = rectangle.y + yOffset;
	double NewY2 = rectangle.y2 - yOffset;

	ScaledRect.SetX(NewX); ScaledRect.SetY(NewY); ScaledRect.SetX2(NewX2); ScaledRect.SetY2(NewY2);
	return ScaledRect;
}

static bool Intersects(GameRectangle RectOne, GameRectangle RectTwo)
{
	int leftA, leftB;
	int rightA, rightB;
	int topA, topB;
	int bottomA, bottomB;

	leftA = RectTwo.x;
	rightA = RectTwo.x + RectTwo.width;
	topA = RectTwo.y;
	bottomA = RectTwo.y + RectTwo.height;

	leftB = RectOne.x;
	rightB = RectOne.x + RectOne.width;
	topB = RectOne.y;
	bottomB = RectOne.y + RectOne.height;

	if(bottomA < topB)
		return false;
	if(topA > bottomB)
		return false;
	if(rightA < leftB)
		return false;
	if(leftA > rightB)
		return false;

	return true;

}

static unsigned int GetNextPowerOfTwo(unsigned int num)
{
	num--;
	num |= num >> 1;
	num |= num >> 2;
	num |= num >> 4;
	num |= num >> 8;
	num |= num >> 16;
	num++;

	return num;
}

static SDL_PixelFormat GetPixelFormat()
{
	SDL_PixelFormat RGBAFormat;
	RGBAFormat.palette = 0; RGBAFormat.colorkey = 0; RGBAFormat.alpha = 0;
	RGBAFormat.BitsPerPixel = 32; RGBAFormat.BytesPerPixel = 4;
	#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	RGBAFormat.Rmask = 0xFF000000; RGBAFormat.Rshift = 0; RGBAFormat.Rloss = 0;
	RGBAFormat.Gmask = 0x00FF0000; RGBAFormat.Gshift = 8; RGBAFormat.Gloss = 0;
	RGBAFormat.Bmask = 0x0000FF00; RGBAFormat.Bshift = 16; RGBAFormat.Bloss = 0;
	RGBAFormat.Amask = 0x000000FF; RGBAFormat.Ashift = 24; RGBAFormat.Aloss = 0;
	#else
	RGBAFormat.Rmask = 0x000000FF; RGBAFormat.Rshift = 24; RGBAFormat.Rloss = 0;
	RGBAFormat.Gmask = 0x0000FF00; RGBAFormat.Gshift = 16; RGBAFormat.Gloss = 0;
	RGBAFormat.Bmask = 0x00FF0000; RGBAFormat.Bshift = 8; RGBAFormat.Bloss = 0;
	RGBAFormat.Amask = 0xFF000000; RGBAFormat.Ashift = 0; RGBAFormat.Aloss = 0;
	#endif

	return RGBAFormat;
}
inline bool operator!= (GameRectangle& One, GameRectangle& Two)
{
	return !(One.x == Two.x && One.y == Two.y && One.width == Two.width && One.height == Two.height);
}


// Gets an OpenGL Color from the specified values; if the color is in SDL_Color format, it switches it to OpenGL Color format.
static OGL_Color GetFixedColor(float r, float g, float b, float a)
{
	if(r > 1.0f)
		r /= 255.0f;

	if(g > 1.0f)
		g /= 255.0f;

	if(b > 1.0f)
		b /= 255.0f;

	if(a > 1.0f)
		a /= 255.0f;

	OGL_Color col = {r, g, b, a};
	return col;
}

template<class T>
static string GetString(const T& t)
{
	stringstream ss;
	ss << t;
	return ss.str();
}

inline int Index(int row, int col, int num_cols)
{
	return (row*num_cols + col);
}

static Range GetRange(int max, int min)
{
	Range range;
	if(max >= min)
	{
		range.max = max;
		range.min = min;
	}
	if(min > max)
	{
		range.max = min;
		range.min = max;
	}
	return range;
}

static int Rand(int min, int max)
{
    if (min>max)
    {
        return max+int((min-max+1)*rand()/(RAND_MAX+1.0));
    }
    else
    {
        return min+int((max-min+1)*rand()/(RAND_MAX+1.0));
    }
} 

static int Rand(Range range)
{
	return Rand(range.min, range.max);
}




static GameRectangle GetRect(int x1, int y1, int x2, int y2)
{
	GameRectangle aRect;
	aRect.x = x1;
	aRect.y = y1;
	int tempW = x2 - x1;
	int tempH = y2 - y1;

	if(tempW < 0)
	{
		aRect.width = (-1)*tempW;
		aRect.x = aRect.x - aRect.width;
		
	}
	else
		aRect.width = tempW;
	if(tempH < 0)
	{
		aRect.height = (-1)*tempH;
		aRect.y = aRect.y - aRect.height;						
	}
	else
		aRect.height = tempH;

	return aRect;
}




inline string RectToString(GameRectangle rect)
{
	stringstream ss;
	ss << "( X:" << rect.x << "  Y:" << rect.y << " W:" << rect.width << " H:" << rect.height;
	return ss.str();
}

static GameRectangle GetCircumscribedRect(int x, int y, double radius)
{
	int Width = radius*2;
	int Height = radius*2;

	int Xpos = x - radius;
	int Ypos = y - radius;

	return GameRectangle(Xpos, Ypos, Width, Height);
}

static wchar_t* CharToWChar(const char* orig)
{
	size_t origsize = strlen(orig) + 1;
    const size_t newsize = 100;
    size_t convertedChars = 0;
    wchar_t wcstring[newsize];
    mbstowcs_s(&convertedChars, wcstring, origsize, orig, _TRUNCATE);

	return wcstring;
}

// Takes the coordinates for a rectangle, and returns a "fixed" rectangle where
// the x1 and y1 are at the top left and the width and height are positive

